﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;

namespace Notoric.Gui.Controls.Adorners
{
    /// <summary>
    /// Implements a control that decorates a <see cref="FrameworkElement"/> by a <see cref="RRMAdorner"/>.
    /// </summary>
    public class RRMDecorator : ContentControl
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="RRMDecorator"/> instance.
        /// </summary>
        public RRMDecorator()
        {
            Unloaded += new RoutedEventHandler(RRMDecorator_Unloaded);
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Occurs when the user has finished moving the decorated object.
        /// </summary>
        /// <remarks>
        /// <b>Operation:</b><br/>
        /// The handler marks the event as handled and resends the data via its own <see cref="MoveCompleted"/> event.
        /// </remarks>
        /// <param name="sender">Object on which the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void adorner_MoveCompleted(object sender, MoveCompletedEventArgs e)
        {
            e.Handled = true;
            MoveCompletedEventArgs args = new MoveCompletedEventArgs(e.Left, e.Top)
            {
                RoutedEvent = MoveCompletedEvent
            };
            RaiseEvent(args);
        }

        /// <summary>
        /// Occurs when the user has finished rotating the decorated object.
        /// </summary>
        /// <remarks>
        /// <b>Operation:</b><br/>
        /// The handler marks the event as handled and resends the data via its own <see cref="RotateCompleted"/> event.
        /// </remarks>
        /// <param name="sender">Object on which the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void adorner_RotateCompleted(object sender, RotateCompletedEventArgs e)
        {
            e.Handled = true;
            RotateCompletedEventArgs args = new RotateCompletedEventArgs(e.RotationAngle)
            {
                RoutedEvent = RotateCompletedEvent
            };
            RaiseEvent(args);
        }

        /// <summary>
        /// Occurs when the user finished resizing the decorated object.
        /// </summary>
        /// <remarks>
        /// <b>Operation:</b><br/>
        /// The handler marks the event as handled and resends the data via its own <see cref="ResizeCompleted"/> event.
        /// </remarks>
        /// <param name="sender">Object on which the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void adorner_ResizeCompleted(object sender, ResizeCompletedEventArgs e)
        {
            e.Handled = true;
            ResizeCompletedEventArgs args = new ResizeCompletedEventArgs(e.Width, e.Height)
            {
                RoutedEvent = ResizeCompletedEvent
            };
            RaiseEvent(args);
        }

        /// <summary>
        /// Occurs when the control is unloaded.
        /// </summary>
        /// <remarks>
        /// <b>Operation:</b><br/>
        /// The handler removes the adorner from the adorner layer.
        /// </remarks>
        /// <param name="sender">Object on which the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void RRMDecorator_Unloaded(object sender, RoutedEventArgs e)
        {
            if (adorner != null)
            {
                AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);
                if (adornerLayer != null)
                {
                    adornerLayer.Remove(adorner);
                }

                adorner = null;
            }
        }

        /// <summary>
        /// Occurs when the value of the <see cref="ShowDecorator"/> dependency property has changed.
        /// </summary>
        /// <remarks>
        /// <b>Operation:</b><br/>
        /// The handler shows or hides the adorner depending on the new value of the property.
        /// </remarks>
        /// <param name="d">Dependency object on which the property has changed</param>
        /// <param name="e">Event data</param>
        private static void ShowDecoratorProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            RRMDecorator decorator = (RRMDecorator)d;
            bool showDecorator = (bool)e.NewValue;

            if (showDecorator)
            {
                decorator.ShowAdorner();
            }
            else
            {
                decorator.HideAdorner();
            }
        }

        #endregion

        #region Routed Event Fields

        /// <summary>
        /// Identifies the <see cref="MoveCompleted"/> routed event.
        /// </summary>
        public static readonly RoutedEvent MoveCompletedEvent = EventManager.RegisterRoutedEvent(
            "MoveCompleted", RoutingStrategy.Bubble, typeof(EventHandler<MoveCompletedEventArgs>), typeof(RRMDecorator));

        /// <summary>
        /// Identifies the <see cref="ResizeCompleted"/> routed event.
        /// </summary>
        public static readonly RoutedEvent ResizeCompletedEvent = EventManager.RegisterRoutedEvent(
            "ResizeCompleted", RoutingStrategy.Bubble, typeof(EventHandler<ResizeCompletedEventArgs>), typeof(RRMDecorator));

        /// <summary>
        /// Identifies the <see cref="RotateCompleted"/> routed event.
        /// </summary>
        public static readonly RoutedEvent RotateCompletedEvent = EventManager.RegisterRoutedEvent(
            "RotateCompleted", RoutingStrategy.Bubble, typeof(EventHandler<RotateCompletedEventArgs>), typeof(RRMDecorator));

        #endregion

        #region Public Events

        /// <summary>
        /// Occurs when the user has finished moving the decorated object.
        /// </summary>
        public event EventHandler<MoveCompletedEventArgs> MoveCompleted
        {
            add { AddHandler(MoveCompletedEvent, value); }
            remove { RemoveHandler(MoveCompletedEvent, value); }
        }

        /// <summary>
        /// Occurs when the user has finished resizing the decorated object.
        /// </summary>
        public event EventHandler<ResizeCompletedEventArgs> ResizeCompleted
        {
            add { AddHandler(ResizeCompletedEvent, value); }
            remove { RemoveHandler(ResizeCompletedEvent, value); }
        }

        /// <summary>
        /// Occurs when the user has finished rotating the decorated object.
        /// </summary>
        public event EventHandler<RotateCompletedEventArgs> RotateCompleted
        {
            add { AddHandler(RotateCompletedEvent, value); }
            remove { RemoveHandler(RotateCompletedEvent, value); }
        }

        #endregion

        #region Dependency Property Fields

        /// <summary>
        /// Identifies the <see cref="ShowDecorator"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty ShowDecoratorProperty =
            DependencyProperty.Register("ShowDecorator", typeof(bool), typeof(RRMDecorator),
            new FrameworkPropertyMetadata(false, new PropertyChangedCallback(ShowDecoratorProperty_Changed)));

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the value indicating whether the adorner should be displayed or not.<br/>
        /// This is a dependency property.
        /// </summary>
        /// <value>
        /// If this value is true then the adorner is visible, otherwise it is hidden.
        /// </value>
        public bool ShowDecorator
        {
            get { return (bool)GetValue(ShowDecoratorProperty); }
            set { SetValue(ShowDecoratorProperty, value); }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Hides the adorner.
        /// </summary>
        private void HideAdorner()
        {
            if (adorner != null)
            {
                adorner.Visibility = Visibility.Hidden;
            }
        }

        /// <summary>
        /// Creates the adorner if it was not created yet and shows it.
        /// </summary>
        private void ShowAdorner()
        {
            if (adorner == null)
            {
                AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);

                if (adornerLayer != null)
                {
                    FrameworkElement decoratedItem = this;
                    Canvas canvas = VisualTreeHelper.GetParent(decoratedItem) as Canvas;
                    adorner = new RRMAdorner(decoratedItem);

                    adorner.MoveCompleted += new EventHandler<MoveCompletedEventArgs>(adorner_MoveCompleted);
                    adorner.ResizeCompleted += new EventHandler<ResizeCompletedEventArgs>(adorner_ResizeCompleted);
                    adorner.RotateCompleted += new EventHandler<RotateCompletedEventArgs>(adorner_RotateCompleted);

                    adornerLayer.Add(adorner);

                    if (ShowDecorator)
                    {
                        adorner.Visibility = Visibility.Visible;
                    }
                    else
                    {
                        adorner.Visibility = Visibility.Hidden;
                    }
                }
            }
            else
            {
                adorner.Visibility = Visibility.Visible;
            }
        }

        #endregion       

        #region Private Fields

        /// <summary>
        /// Holds a reference to the adorner.
        /// </summary>
        private RRMAdorner adorner;

        #endregion
    }
}
